package com.xyzwps.collections.set

import com.xyzwps.collections.Range
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test

import static org.junit.jupiter.api.Assertions.*

class TestSkipListSet {

    @Test
    void testCommon() {
        TestSet.testCommon { new SkipListSet<>() }
        for (int i : Range.create(36)) {
            TestSet.testCommon { new SkipListSet<>(i) }
        }
    }

    /**
     * 跳表应该是个有序表
     */
    @Test
    void testOrder() {

        def COUNT = 213
        comparable:
        {
            def set = new SkipListSet<Integer>()
            for (int i : Range.create(COUNT)) set.add(i)

            Integer times = 0, curr = null
            for (def e : set) {
                if (curr != null) {
                    assertTrue curr < e
                    times++
                }
                curr = e
            }
            assertEquals times, COUNT
        }

        comparator:
        {
            def set = new SkipListSet<Person>(PERSON_COMPARATOR)
            for (int i : Range.create(COUNT)) set.add(new Person(id: "$i"))

            int times = 0
            Person curr = null
            for (def p : set) {
                if (curr != null) {
                    assertTrue PERSON_COMPARATOR.compare(curr, p) < 0
                    times++
                }
                curr = p
            }
            assertEquals times, COUNT
        }
    }

    @Nested
    class WithComparator {

        @Test
        void testAdd() {
            def set = new SkipListSet<Person>(PERSON_COMPARATOR)
            int COUNT = 123
            for (int i : Range.create(COUNT - 1)) {
                set.add(new Person(id: "$i", name: "name-$i"))
                assertEquals set.size(), i + 1
            }
        }

        @Test
        void testContains() {
            def set = new SkipListSet<Person>(PERSON_COMPARATOR)
            int COUNT = 145
            for (int i : Range.create(COUNT - 1)) {
                set.add(new Person(id: "$i", name: "name-$i"))
            }

            for (int i : Range.create(-121, COUNT * 2)) {
                def person = new Person(id: "$i")
                if (0 <= i && i < COUNT) {
                    assertTrue person in set
                    assertTrue set.has(person)
                } else {
                    assertFalse person in set
                    assertFalse set.has(person)
                }
            }
        }

        @Test
        void testRemove() {
            def set = new SkipListSet<Person>(PERSON_COMPARATOR)
            int COUNT = 145
            for (int i : Range.create(COUNT - 1)) {
                set.add(new Person(id: "$i", name: "name-$i"))
            }

            for (int i : Range.create(-121, COUNT * 2)) {
                def person = new Person(id: "$i")
                if (i < 0) {
                    assertFalse set.remove(person)
                    assertEquals set.size(), COUNT
                } else if (i < COUNT) {
                    assertTrue set.remove(person)
                    assertFalse person in set
                    assertEquals set.size(), COUNT - 1 - i
                } else {
                    assertFalse set.remove(person)
                    assertEquals set.size(), 0
                }
            }
        }

        @Test
        void testClear() {
            def set = new SkipListSet<Person>(PERSON_COMPARATOR)
            int COUNT = 145
            for (int i : Range.create(COUNT - 1)) {
                set.add(new Person(id: "$i", name: "name-$i"))
            }

            set.clear()
            assertEquals set.size(), 0

            for (int i : Range.create(-121, COUNT * 2)) {
                def person = new Person(id: "$i")
                assertFalse person in set
                assertFalse set.has(person)
            }
        }

        @Test
        void testIterator() {
            def set = new SkipListSet<Person>(PERSON_COMPARATOR)
            final int COUNT = 133
            for (int i : Range.create(COUNT)) set.add(new Person(id: "$i"))

            int times = 0
            for (def p : set) {
                assertTrue p in set
                times++
            }
            assertEquals times, COUNT + 1
        }
    }

    class Person {
        String id, name
    }

    static Comparator<Person> PERSON_COMPARATOR = new Comparator<Person>() {
        @Override
        int compare(Person o1, Person o2) {
            Objects.requireNonNull(o1)
            Objects.requireNonNull(o2)
            Objects.requireNonNull(o1.id)
            Objects.requireNonNull(o2.id)
            return o1.id <=> o2.id
        }
    }

}
